package com.spx;

import java.io.*;

import android.util.Log;

/**
 * SPX 数据
 * @author Administrator
 */
public final class SpriteXData{
	private static final int SPX_HEADER=0x53505258;
	private static final int SPX_MIN_VERSION=34;
	private static final int SPX_MAX_VERSION=34;
	
//	/**
//	 * 图像ID列表
//	 */
//	private short imageIDTable;
//	/**
//	 * 动画ID列表
//	 */
//	private short[] actionIDTable;
//	/**
//	 * 图像尺寸列表
//	 */
//	private short[] imageSizeTable;
	/**
	 * 图块数据对象组
	 */
	private SpxTileSet tileSets;
	/**
	 * 动作帧数据对象组
	 */
	private SpxFrame[] frames;
	/**
	 * 动画数据对象组
	 */
	SpxAction[] actions;
	/**
	 * 图像资源对象组
	 */
	private Image images;

	private SpriteXData(){}

	public final static SpriteXData loadSpriteX(ArrayByteInput is){
		if(is==null){
			throw new NullPointerException("InputStream is null!");
		}
		try{
			int header=is.readInt();	//文件头
			if(header!=SPX_HEADER){
				throw new NullPointerException("文件头不正确!");
			}
			int version=is.readUByte();	//版本号
			if(version < SPX_MIN_VERSION || version > SPX_MAX_VERSION){
				throw new NullPointerException("版本不正确!");
			}
			
			int flag = is.readUByte();	//是否使用拆分模式
			
			int tileSetCount=is.readInt();	//图块数量 .
			SpxTileSet tileSets=new SpxTileSet();
			tileSets.tiles = new SpxRect[tileSetCount];
			if(!readTileSets(is,tileSets)){
				return null;
			}
			
			int frameCount =is.readInt();	//帧数量
			SpxFrame[] frames=new SpxFrame[frameCount];
			if(!readFrames(is,frames)){
				return null;
			}
			int actionCount=is.readInt(); //动作数量
			SpxAction[] actions = new SpxAction[actionCount];
			if(!readActions(is,actions)){
				return null;
			}
			
			SpriteXData spx=new SpriteXData();
/*
			spx.imageIDTable=imageIDTable;
			spx.imageSizeTable=imageSizeTable;
			spx.actionIDTable=actionIDTable;
			spx.tileSets=tileSets;
			spx.frames=frames;
			spx.actions=actions;
			spx.images=new Image[imageIDTableCount];*/
			
			spx.tileSets = tileSets;
			spx.frames = frames;
			spx.actions = actions;
			return spx;
		}catch(Exception ex){
			ex.printStackTrace();
			return null;
		} 
	}
	
	//读取数据文件
	public final static SpriteXData loadSpriteX(String fileName){
		if(fileName==null){
			return null;
		}
		SpriteXData spx=null;
		try{
			ArrayByteInput is=new ArrayByteInput(fileName);
			spx = loadSpriteX(is);
			is.close();
			is=null;
		}catch(IOException e){
			e.printStackTrace();
		}
		return spx;
	}

	//加载图片
	public final boolean loadImage(String path){
		Image image=Image.createImage(path);
		if(image == null){
			return false;
		}
		else {
			this.images = image;
		}
		return true;
	}

	public int getActionCount(){
		return actions.length;
	}
	
	final SpxFrame getSpxFrame(int index){
		if(index<0||index>=frames.length){
			throw new IndexOutOfBoundsException("index:"+index+"越界！");
		}
		return frames[index];
	}
	
	void drawFrame(SpriteX2 sprite,LGraphics context,int x,int y,int actionIndex,int sequenceIndex){
		SpxAction action=actions[actionIndex];
		int frameIndex=action.frameSequences[sequenceIndex];
		SpxFrame frame=frames[frameIndex];
		SpxTilePatch[] patchs=frame.patchs;
		for(int i=0;i<patchs.length;++i){
			if(patchs[i]!= null){
				patchs[i].drawPatch(this,sprite,context,images,x,y);
			}
		}
	}
	
/************************************************************************
 * 加载数据文件
 *************************************************************************/
	private final static boolean readTileSets(ArrayByteInput is,SpxTileSet tileSets) throws Exception{
		for(int i = 0; i < tileSets.tiles.length; ++i) {
			tileSets.tiles[i] = readRect(is);
		}
		return true;
	}

	private final static boolean readFrames(ArrayByteInput is, SpxFrame[] frames) throws Exception{
		for(int i = 0; i < frames.length; ++i) {
			SpxFrame frame=new SpxFrame();
			frames[i] = frame;
			int patchCount = is.readInt();
			int collideCount = is.readInt();
			int refpointCount = is.readInt();
			if (patchCount != 0) {
				frames[i].patchs = new SpxTilePatch[patchCount];
			}
			if (collideCount != 0) {
				frames[i].collides = new SpxRect[collideCount];
			}
			if (refpointCount != 0) {
				frames[i].refpoints = new SpxPoint[refpointCount];
			}
			
			SpxRect rect = new SpxRect();	//帧在坐标轴中的相对位置，Y向下为+，X向右为+；
			rect.top = is.readShort();
			rect.bottom = is.readShort();
			rect.left = is.readShort();
			rect.right = is.readShort();
			frames[i].relativePos = rect;
			
			for(int j = 0;j < patchCount; ++j) {
				SpxTilePatch patch = new SpxTilePatch();
				frames[i].patchs[j] = patch;
				frames[i].patchs[j].tileIndex = is.readShort();	//单块图块索引
				frames[i].patchs[j].x = is.readShort();			//单块图块相对坐标X
				frames[i].patchs[j].y = is.readShort();			//单块图块相对坐标Y
				frames[i].patchs[j].transform = is.readShort(); //单块图块变换标记位
			}
			for(int j = 0;j < collideCount; ++j) {				//碰撞矩形
				frames[i].collides[j] = readRect(is);
			}
			for(int j = 0;j < refpointCount; ++j) {				//参考点
				frames[i].refpoints[j] = readPoint(is);
			}	
		}
		return true;
	}

	private final static boolean readActions(ArrayByteInput is,SpxAction[] actions) throws Exception{
		for(int i=0;i<actions.length;++i){
			
			SpxAction action = new SpxAction();
			actions[i] = action;
			int frameCount = is.readInt();			//单个动作包含的帧数
			
			actions[i].mode = is.readByte();
			actions[i].mode &= 0xff;	//1位帧延时标记位
			is.readInt();				//4位保留位
			
			if (frameCount != 0) {
				actions[i].frameSequences = new short[frameCount];
				if (actions[i].mode == SpxAction.SPX_DELAY) {
					actions[i].frameDelays = new short[frameCount];
				}
			}
			
			for (int j = 0; j < frameCount; j++) {
				actions[i].frameSequences[j] = is.readShort();
				if (actions[i].frameDelays != null) {
					actions[i].frameDelays[j] = is.readShort();
				}
			}
		}
		return true;
	}
	
	private final static SpxRect readRect(ArrayByteInput is) throws IOException{
		SpxRect rect = new SpxRect();
		rect.left = is.readShort();
		rect.top = is.readShort();
		rect.right = rect.left + is.readShort();
		rect.bottom = rect.top + is.readShort();
		return rect;
	}
	
	private final static SpxPoint readPoint(ArrayByteInput is) throws IOException{
		SpxPoint point = new SpxPoint();
		point.x = is.readShort();
		point.y = is.readShort();
		return point;
	}
	
	/**
	 * SPX 帧-图块贴图
	 * @author Administrator
	 */
	final static class SpxTilePatch{
		/**
		 * 图块数据对象索引
		 */
		short tileSetIndex;
		/**
		 * 图块对象的图块索引
		 */
		short tileIndex;
		short x;
		short y;
		/**
		 * 翻转参数
		 */
		short transform;

		private final void drawPatch(SpriteXData spx,SpriteX2 sprite,LGraphics context,Image images,int x,int y){
			final SpxTileSet tileSet=spx.tileSets;
			final SpxRect tile=tileSet.tiles[tileIndex];
			final Image image= images;
			int tt=LTrans.TRANSFORM_TABLE[sprite.transform][transform];
			SpxRect dest=new SpxRect();
			dest.setRect(this.x,this.y,this.x+tile.getWidth(),this.y+tile.getHeight());
			dest.transform(sprite.transform);
			dest.translate(x,y);
			dest.normalize();
			sprite.drawRegion(context,image,tile.left,tile.top,tile.getWidth(),tile.getHeight(),
						tt,dest.left,dest.top);
			
		}
	}
	
	/**
	 * SPX 帧数据对象
	 * @author Administrator
	 */
	final static class SpxFrame{
		static final int SPX_PATCH_TILE=1;
		/**
		 * 帧标志
		 */
		int flagBits;
		//图块数
		int tilesCnt;
		//矩形数
		int collidesCnt;
		//参考点数
		int refpointsCnt;
		
		SpxRect relativePos;
		
		/**
		 * 图块区域
		 */
		SpxTilePatch[] patchs;
		/**
		 * 矩形碰撞区域
		 */
		SpxRect[] collides;
		
		/**
		 * 参考点区域
		 */
		SpxPoint[] refpoints;
	}
	
	/**
	 * SPX 图块数据对象
	 * @author Administrator
	 */
	final static class SpxTileSet{
		static final int SPX_TILE_INDEX=1;
		static final int SPX_TILE_CLIP=2;
		/**
		 * 对应的 图像ID
		 */
	    int imageID;
	    /**
	     * 对应的图像索引
	     */
	    int imageIndex;
	    /**
	     * 储存裁剪区域
	     */
	    SpxRect[] tiles;
	    
	}
	
	/**
	 * SPX 动画数据对象
	 * @author Administrator
	 */
	final static class SpxAction{
		static final int SPX_DELAY=1;
		static final int SPX_NODELAY=2;
		/**
		 * 模式    SPX_DELAY   SPX_NODELAY
		 */
		int mode;
		/**
		 * 储存帧列表
		 */
		short[] frameSequences;
		/**
		 * 帧延时列表
		 */
		short[] frameDelays;
	}
}
